#include "PropertyList.h"
#include "Property.h"

CPropertyList::CPropertyList(CType* InOwnerType)
{
    OwnerType=InOwnerType;
}

TVector<CProperty*> &  CPropertyList::GetProperties()
{
    return Properties;
}

CProperty* CPropertyList::GetProperty(uint64_t Index)
{
    return Properties[Index];
}

CProperty *CPropertyList::FindProperty(const CString &InPropertyName)
{
    for(auto& Property: Properties)
    {
        if(Property->GetName()==InPropertyName)
        {
            return Property;
        }
    }

    return nullptr;
}

CNativeFieldProperty *CPropertyList::FindNativeFieldPropertyByOffset(int64_t Offset)
{
    for(auto& Property: FieldProperties)
    {
        if(Property->GetNativeFieldOffset()==Offset)
        {
            return reinterpret_cast<CNativeFieldProperty*>(Property);
        }
    }

    return nullptr;
}

void CPropertyList::AddProperty(CProperty* InProperty)
{
    Properties.Add(InProperty);

    if(InProperty->IsField())
    {
        FieldProperties.Add(InProperty);

        if(InProperty->IsStatic())
        {
            StaticFieldProperties.Add(InProperty);
        }
        else
        {
            NonStaticFieldProperties.Add(InProperty);
        }
    }
}

void CPropertyList::CopyProperties(
    const CPropertyList *Src
    , CPropertyList *Dest
    )
{
    Dest->Properties=Src->Properties;
    Dest->FieldProperties=Src->FieldProperties;
    Dest->StaticFieldProperties=Src->StaticFieldProperties;
    Dest->NonStaticFieldProperties=Src->NonStaticFieldProperties;
}

void CPropertyList::AppendProperties(const CPropertyList *Src, CPropertyList *Dest, bool bSort)
{
    Dest->Properties.Append(Src->Properties);
    Dest->FieldProperties.Append(Src->FieldProperties);
    Dest->StaticFieldProperties.Append(Src->StaticFieldProperties);
    Dest->NonStaticFieldProperties.Append(Src->NonStaticFieldProperties);

    if(bSort)
    {
        //sort field properties by FieldIndex

        Dest->FieldProperties.Sort([](CProperty* A, CProperty* B)
        {
            return A->FieldProperty->GetFieldIndex() < B->FieldProperty->GetFieldIndex();
        });

        Dest->StaticFieldProperties.Sort([](CProperty* A, CProperty* B)
        {
            return A->FieldProperty->GetFieldIndex() < B->FieldProperty->GetFieldIndex();
        });

        Dest->NonStaticFieldProperties.Sort([](CProperty* A, CProperty* B)
        {
            return A->FieldProperty->GetFieldIndex() < B->FieldProperty->GetFieldIndex();
        });
    }
}

uint64_t CPropertyList::GetNonStaticFieldHash(const void *InInstance) const
{
    uint64_t Hash=0;
    for(auto& Field: NonStaticFieldProperties)
    {
        auto FieldValue= Field->FieldProperty->GetValuePointer(InInstance);
        if(Hash==0)
        {
            Hash=Field->GetType().BasicType->GetInstanceHash(FieldValue);
            continue;
        }
        Hash = WH::HashCombine(Hash,Field->GetType().BasicType->GetInstanceHash(FieldValue));
    }

    return Hash;
}

bool CPropertyList::IsNonStaticFieldEqual(const void *A, const void *B) const
{
    for(auto& Field: NonStaticFieldProperties)
    {
        auto FieldValueA= Field->FieldProperty->GetValuePointer(A);
        auto FieldValueB= Field->FieldProperty->GetValuePointer(B);
        if(!Field->GetType().BasicType->IsInstanceEqual(FieldValueA,FieldValueB))
        {
            return false;
        }
    }

    return true;
}
